package Railroad.Communication;

import Railroad.Communication.Codes.CommunicationCodes;
import Railroad.Components.Switch;
import Railroad.Components.SwitchStatus;
import Railroad.Components.TrackNode;
import Railroad.Zoznam;

public class MessageParser {
    private final Zoznam zoznam;
    private final CommDriver driver;
    
    public MessageParser(Zoznam z, CommDriver driver) {
        this.zoznam = z;
        this.driver = driver;
    }

    private void parseMessage(byte code) {
        int length = getMessageLength(code);
        CommData data = driver.receive(length);
        
        byte readCode = data.get();
        if (code != readCode) {
            System.out.println("chyba v citani: ocakavany kod " + code + "," +
                                " prisiel " + readCode);
            code = readCode;
        }        
        //System.out.println("< " + readCode);
        
        switch (code) {
            case CommunicationCodes.In.Ping:
                parsePing(data);
                break;
            case CommunicationCodes.In.ClearanceStatusResponse:
                parseClearanceStatusResponse(data);
                break;
            case CommunicationCodes.In.GetSwitchStatusResponse:
                parseGetSwitchStatusResponse(data);
                break;
        }
    }

    private int getMessageLength(byte code) {
        switch (code) {
            case CommunicationCodes.In.Ping:
                return 1;
            case CommunicationCodes.In.ClearanceStatusResponse:
                return 2;
            case CommunicationCodes.In.GetSwitchStatusResponse:
                return 2;
        }
        return 0;
    }

    private void parsePing(CommData data) {
    }

    public void parseClearanceStatusResponse() {
        parseMessage(CommunicationCodes.In.ClearanceStatusResponse);
    }
    
    private void parseClearanceStatusResponse(CommData data) {
        int mask = data.get();
        
        int count = zoznam.dajPocetObsaditelnych();
        for (byte i = 0; i < count; i++) {
            TrackNode node = zoznam.vratObsaditelny(i);
            boolean obsadeny = (mask & (1<<i)) != 0;
            node.setBusy(obsadeny);
        }
    }
    
    public void parseGetSwitchStatusResponse() {
        parseMessage(CommunicationCodes.In.GetSwitchStatusResponse);
    }

    private void parseGetSwitchStatusResponse(CommData data) {
        int mask = data.get();
        
        int count = zoznam.dajPocetVyhybiek();
        for (byte i = 0; i < count; i++) {
            Switch sw = zoznam.vratVyhybku(i);
            int status = (mask >> (2*i)) & 0x03;
            SwitchStatus st = status == 0 ? SwitchStatus.UNKNOWN : (status == 1 ? SwitchStatus.STRAIGHT : SwitchStatus.SIDE);
            sw.prestav(st);
        }
    }
}
